package com.wsoft.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wsoft.constant.RedisKeyConstant;
import com.wsoft.core.exception.Asserts;
import com.wsoft.core.service.RedisService;
import com.wsoft.core.utils.JwtTokenUtil;
import com.wsoft.core.utils.LoginUserUtil;
import com.wsoft.entity.BaseEntity;
import com.wsoft.service.IMemberCacheService;
import com.wsoft.service.IMemberCommonService;
import com.wsoft.service.IVerificationCodeService;
import com.wsoft.system.dto.LoginDTO;
import com.wsoft.system.entity.*;
import com.wsoft.system.mapper.SysAccountMapper;
import com.wsoft.system.mapper.SysMemberMapper;
import com.wsoft.system.mapper.SysMemberOrgRoleRelationMapper;
import com.wsoft.system.query.account.PwdQuery;
import com.wsoft.system.query.account.StyleQuery;
import com.wsoft.system.service.*;
import com.wsoft.utils.RsaUtil;
import com.wsoft.vo.LoginUserDetail;
import com.wsoft.vo.LoginUserVO;
import com.wsoft.vo.config.LoginInfoRespVO;
import com.wsoft.vo.config.MultipleOrgRespVO;
import com.wsoft.vo.config.SystemConfigRespVO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.wsoft.constant.CommonConstant.YESNO_NO;
import static com.wsoft.constant.RedisKeyConstant.USER_INFO_CACHE;

/**
 * <p>
 * 账号表 服务实现类
 * </p>
 *
 * @author juiet
 * @since 2024年09月03日 10:35:39
 */
@Service
public class SysAccountServiceImpl extends ServiceImpl<SysAccountMapper, SysAccountEntity> implements ISysAccountService {

    @Value("${wsoft.login.error.count}")
    private Integer loginErrorCount;

    @Value("${wsoft.rsa.privateKey}")
    private String privateKey;
    @Resource
    private IVerificationCodeService verificationCodeService;
    @Resource
    private RedisService redisService;
    @Resource
    private IMemberCommonService memberCommonService;
    @Resource
    private JwtTokenUtil jwtTokenUtil;
    @Resource
    private ITsConfigService tsConfigService;
    @Resource
    private ITsConfigInfoService tsConfigInfoService;
    @Resource
    private SysMemberMapper memberMapper;
    @Resource
    private ISysMemberService memberService;
    @Resource
    private ISysOrganizationService organizationService;
    @Resource
    private SysMemberOrgRoleRelationMapper sysMemberOrgRoleRelationMapper;
    @Resource
    private ISysAccountService accountService;

    @Override
    public String login(LoginDTO dto) {
        //1、验证验证码
        verificationCodeService.checkImageCode(dto.getImageKey(), dto.getImageCode());

        //2、失败登录次数验证
        String keyVerification = RedisKeyConstant.LOGIN_USER_COUNT + dto.getUsername();
        int count = redisService.get(keyVerification) == null ? 0 : Integer.parseInt(redisService.get(keyVerification).toString());
        if (count >= loginErrorCount) {
            //连续登录超过5次,请5分钟后再试！
            Asserts.fail("[login.error.times]");
        }
        redisService.set(keyVerification, count + 1, 300);

        //3、密码验证
        UserDetails userDetails = memberCommonService.loadUserByUsername(dto.getUsername());
        if (userDetails == null) {
            /*用户名不存在*/
            Asserts.fail("[login.error.noUser]");
        }
        String dbPw = userDetails.getPassword();
        String rsaPassword = RsaUtil.decryptDataOnJava(dto.getPassword(), privateKey);
        if (!StrUtil.equals(dbPw, rsaPassword)) {
            /*密码错误*/
            Asserts.fail("[login.error.password]");
        }

        //4、生成token
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);
        String token = jwtTokenUtil.generateToken(userDetails);

        //5、重置登录次数
        redisService.set(keyVerification, 0, 300);
        return token;
    }

    @Override
    public SystemConfigRespVO getSystemConfig(String username) {
        List<TsConfigEntity> list = tsConfigService.listConfig();
        if (CollUtil.isEmpty(list)) {
            Asserts.fail("[config.error.empty]");
        }
        // 总配置
        TsConfigEntity config = list.get(0);

        // 查询用户信息
        LoginUserDetail loginUserDetail = (LoginUserDetail) memberCommonService.loadUserByUsername(username);

        //如果用户为空，拉取配置表
        if (StrUtil.isBlank(username) || loginUserDetail == null) {
            return Convert.convert(SystemConfigRespVO.class, config);
        }

        LoginUserVO loginUserVO = loginUserDetail.getLoginUserVO();
        Long memberId = loginUserVO.getId();
        Long loginOrgId = loginUserVO.getLoginOrgId();

        Integer isUserInit = config.getIsUserInit() != null ? config.getIsUserInit() : 0;
        Integer isOrgInit = config.getIsOrgInit() != null ? config.getIsOrgInit() : 0;

        // 加载用户自定义环境配置
        if (1 == isUserInit) {
//            TsConfigInfoEntity configInfo = tsConfigInfoService.getOne(Wrappers
//                    .lambdaQuery(TsConfigInfoEntity.class)
//                    .eq(TsConfigInfoEntity::getMemberId, memberId)
//                    .eq(BaseEntity::getDeleted, YESNO_NO)
//            );
            //加载用户自定义配置
            TsConfigInfoEntity configInfo = multipleConfigInfo(memberId);

            if (configInfo != null) {
                return Convert.convert(SystemConfigRespVO.class, configInfo);
            }
        }

        // 加载组织的环境配置
        if (isOrgInit == 1) {
            // 加载当前登录组织链环境配置
            if (loginOrgId != null) {
                TsConfigInfoEntity lookupOrgConfig = lookupOrgConfig(loginOrgId);
                if (lookupOrgConfig != null) {
                    return Convert.convert(SystemConfigRespVO.class, lookupOrgConfig);
                }
            }

            // 加载所有关联组织链环境配置
            List<SysMemberOrgRoleRelationEntity> entities = sysMemberOrgRoleRelationMapper.selectList(Wrappers
                    .lambdaQuery(SysMemberOrgRoleRelationEntity.class)
                    .eq(SysMemberOrgRoleRelationEntity::getMemberId, memberId)
                    .eq(BaseEntity::getDeleted, YESNO_NO)
            );
            if (CollUtil.isNotEmpty(entities)) {
                List<Long> orgIds = entities.stream()
                        .map(SysMemberOrgRoleRelationEntity::getOrgId)
                        .distinct()
                        .collect(Collectors.toList());

                for (Long orgId : orgIds) {
                    // 遍历关联组织查找配置文件
                    TsConfigInfoEntity lookupOrgConfig = lookupOrgConfig(orgId);
                    if (lookupOrgConfig != null) {
                        return Convert.convert(SystemConfigRespVO.class, lookupOrgConfig);
                    }
                }
            }

        }

        // 加载默认总配置
        return Convert.convert(SystemConfigRespVO.class, config);
    }


    private TsConfigInfoEntity lookupOrgConfig(Long curOrgId) {
        TsConfigInfoEntity configInfo;
        List<SysOrganizationEntity> allOrgWithCache = organizationService.listAllOrgWithCache();
        if (CollUtil.isEmpty(allOrgWithCache)) {
            Asserts.fail("[cache.error.empty.allOrgWithCache]");
        }

        Map<Long, SysOrganizationEntity> orgParentMap = allOrgWithCache.stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));
        // 尝试循环加载组织配置
        do {
            // 加载当前组织的环境变量
            configInfo = tsConfigInfoService.getConfigInfoByOrg(curOrgId);

            if (configInfo != null) {
                return configInfo;
            }

            // 否则继续往上一级查找
            curOrgId = orgParentMap.get(curOrgId).getPaId();

        } while (curOrgId != null && curOrgId.longValue() != 0);

        return null;
    }

    @Resource
    private ISysMenuService iSysMenuService;

    @Override
    public LoginInfoRespVO getLoginInfo() {
        LoginUserDetail loginUserDetail = LoginUserUtil.getUserInfo();
        if (loginUserDetail == null) {
            Asserts.fail("[member.error.info.empty]");
        }

        LoginInfoRespVO respVO = new LoginInfoRespVO();
        respVO.setLoginUser(loginUserDetail.getLoginUserVO());
        respVO.setSystemConfig(getSystemConfig(loginUserDetail.getUsername()));
        respVO.setMenuList(memberService.treeMenuListByMemberId(loginUserDetail.getLoginUserVO().getId()));
        return respVO;
    }

    @Resource
    private IMemberCacheService memberCacheService;

    @Override
    public MultipleOrgRespVO getMultipleOrg() {
        LoginUserDetail loginUserDetail = LoginUserUtil.getUserInfo();
        if (loginUserDetail == null) {
            Asserts.fail("[member.error.info.empty]");
        }

        MultipleOrgRespVO respVO = new MultipleOrgRespVO();

        LoginUserVO loginUserVO = loginUserDetail.getLoginUserVO();
        List<SysOrganizationEntity> organizations = organizationService.selectOrgBy(loginUserVO.getId());
        if (CollUtil.isEmpty(organizations)) {
            Asserts.fail("[org.relation.error.empty]");
        }
        doWithSameOrgName(organizations);
        respVO.setOrgList(organizations);

        return respVO;
    }

    private void doWithSameOrgName(List<SysOrganizationEntity> orgs) {
        List<SysOrganizationEntity> list = organizationService.listAllOrgWithCache();
        Map<Long, SysOrganizationEntity> orgMap = list.stream().collect(Collectors.toMap(SysOrganizationEntity::getOrgId, Function.identity()));

        if (CollUtil.isEmpty(orgs)) {
            return;
        }
        Map<String, List<SysOrganizationEntity>> nameMap = orgs.stream().collect(Collectors.groupingBy(SysOrganizationEntity::getName));
        for (Map.Entry<String, List<SysOrganizationEntity>> each : nameMap.entrySet()) {
            List<SysOrganizationEntity> eachValue = each.getValue();
            if (eachValue != null && eachValue.size() > 1) {
                // 同名重复处理（parent+name）
                for (SysOrganizationEntity e : eachValue) {
                    // 获取上级组织名称
                    SysOrganizationEntity thisOrg = orgMap.get(e.getId());
                    Long paId = thisOrg.getPaId();
                    if (paId != null) {
                        SysOrganizationEntity parentOrg = orgMap.get(paId);
                        e.setName(parentOrg.getName() + "-" + e.getName());
                    }
                }
            }
        }
    }


    @Override
    public void changeLoginOrg(Long orgId) {
        LoginUserDetail loginUserDetail = LoginUserUtil.getUserInfo();
        if (loginUserDetail == null) {
            Asserts.fail("[member.error.info.empty]");
        }

        LoginUserVO loginUserVO = loginUserDetail.getLoginUserVO();
        List<SysOrganizationEntity> organizations = organizationService.selectOrgBy(loginUserVO.getId());
        if (CollUtil.isEmpty(organizations)) {
            Asserts.fail("[org.relation.error.empty]");
        }

        Optional<SysOrganizationEntity> find = organizations.stream().filter(e -> e.getId() != null && e.getId().equals(orgId)).findFirst();
        if (!find.isPresent()) {
            Asserts.fail("[org.relation.error.change.failed.auth]");
        }

        // 更新登录组织
        SysOrganizationEntity organization = find.get();
        int update = memberMapper.update(Wrappers
                .lambdaUpdate(SysMemberEntity.class)
                .set(SysMemberEntity::getLoginOrgId, organization.getOrgId())
                .set(SysMemberEntity::getLoginOrgCode, organization.getCode())
                .set(SysMemberEntity::getLoginOrgName, organization.getName())
                .eq(BaseEntity::getId, loginUserVO.getId())
        );
        if (update > 0) {
            // 缓存数据
            loginUserVO.setLoginOrgId(organization.getOrgId());
            loginUserVO.setLoginOrgCode(organization.getCode());
            loginUserVO.setLoginOrgName(organization.getName());
            memberCacheService.cacheMember(loginUserDetail);
        }
    }

    @Override
    public TsConfigInfoEntity multipleConfigInfo(Long memberId) {
        Object object = redisService.get(RedisKeyConstant.CONFIG_INFO_MEMBER + memberId);
            if (object instanceof TsConfigInfoEntity) {
                return (TsConfigInfoEntity) object;
            }
        QueryWrapper<TsConfigInfoEntity> query =   new QueryWrapper<>();
        query.lambda().eq(TsConfigInfoEntity::getMemberId,memberId);
        TsConfigInfoEntity entity = tsConfigInfoService.getOne(query);
        //存缓存
        redisService.set(RedisKeyConstant.CONFIG_INFO_MEMBER + memberId,entity);
        return entity;
    }

    @Override
    public void updatePwd(PwdQuery query) {
        QueryWrapper<SysAccountEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(SysAccountEntity::getMemberId,query.getMemberId());
        SysAccountEntity entity = getOne(queryWrapper);
        String rsaPassword = RsaUtil.decryptDataOnJava(query.getOldPassword(), privateKey);
        if (!StrUtil.equals(entity.getLoginPw(), rsaPassword)) {
            /*密码错误*/
            Asserts.fail("[login.error.password]");
        }
        if (!StrUtil.equals(query.getNewPassword(), query.getConfirmPassword())) {
            /*确认密码错误*/
            Asserts.fail("[login.inconsistent.password]");
        }
        boolean b = update(Wrappers
                .lambdaUpdate(SysAccountEntity.class)
                .set(SysAccountEntity::getLoginPw, query.getNewPassword())
                .eq(SysAccountEntity::getMemberId, query.getMemberId())
        );
        if (b){
            //更新缓存
            redisService.del(USER_INFO_CACHE+entity.getLoginName());
            memberCommonService.loadUserByUsername(entity.getLoginName());
        }
    }

    @Override
    public void updateStyle(StyleQuery query) {
        update(Wrappers
                .lambdaUpdate(SysAccountEntity.class)
                .set(SysAccountEntity::getConfigLayout,query.getConfigLayout())
                .set(SysAccountEntity::getConfigLocation,query.getConfigLocation())
                .set(SysAccountEntity::getConfigSkin,query.getConfigSkin())
                .eq(SysAccountEntity::getMemberId,query.getMemberId())
        );
    }
}
